from rest_framework.response import Response
from rest_framework import status
from datetime import *
from dbs_insert.models import DfeProject, DfeTopic, DfeDatabase
import random
import hashlib
import re
import pymysql
from dbswebservice import settings
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
import paramiko

# CMD_LIST = ['cd %s;%s']


class SSHClinetServer:
    """
    連接操作
    """

    def __init__(self, host, port, user, password):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.ssh = None

    def login_server(self):
        """
        連接ssh
        :return:
        """
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # 目的是接受不在本地Known_host文件下的主机。
        ssh.connect(hostname=self.host, port=self.port, username=self.user, password=self.password)  # 連接
        self.ssh = ssh

    def execute_cmd(self, cmd):
        """
        執行命令
        :param cmd:
        :return 命令結果:
        """
        dins, stdout, stderr = self.ssh.exec_command(cmd,timeout=20)
        return dins, stdout, stderr

    def logout_server(self):
        """
        關閉連接
        :return:
        """
        self.ssh.close()


def response_origin(*args, **kwargs):
    res = Response(*args, **kwargs)
    res['Access-Control-Allow-Origin'] = '*'
    res["Access-Control-Allow-Credentials"] = "true"
    res['Content-Type'] = 'application/json'
    return res


def is_data(request, method, *args, **kwargs):
    """
    获取request中的表单数据，验证数据无误返回一个字典，如果有异常数据会返回一个Response对象
    调用格式如：is_valid(request, "POST", "uid", username=None, role=None)
    :param request:
    :param method:
    :param kwargs:
    :return:
    """
    keys = list(args) + list(kwargs.keys())
    for key in keys:  # 设置第一种获取方式（获取Form表单格式数据）
        if method == "GET":
            value = request.GET.get(key, None)
        elif method == "POST":
            value = request.POST.get(key, None)
        elif method == "PUT":
            # value = request.PUT.get(key, None)
            value = request.data[key]

        if not value:  # 设置第二种获取方式（获取转为JSON的数据格式）
            value = request.data[key]

        if not value:  # 为空则返回
            return response_origin({"message": "Parameter '%s' cannot be empty!" % key},
                                   status=status.HTTP_400_BAD_REQUEST)
        else:
            kwargs[key] = value
    return kwargs


def only_num():
    nowtime = datetime.now().strftime("%Y%m%d%H%M%S")  # 生成当前的时间
    random_num = random.randint(0, 100)  # 生成随机数n,其中0<=n<=100
    if random_num <= 10:
        random_num = str(0) + str(random_num)
    uniqueNum = str(nowtime) + str(random_num)
    return uniqueNum[5:16]


def get_ip(request):
    """
    获取用户的IP地址
    """
    try:
        real_ip = request.META['HTTP_X_FORWARDED_FOR']
        regip = real_ip.split(",")[0]
    except:
        try:
            regip = request.META['REMOTE_ADDR']
        except:
            regip = ""
    return regip


def make_standard_dict():
    """
    返回标准格式的字典
    :return:
    """
    context = {
        'status': 0,
        'errmsg': '',
        'payload': {}
    }
    return context


def make_false_dict():
    '''
    返回标准错误格式的字典
    :return:
    '''
    context = {
        'status': 1,
        'errmsg': '',
        'payload': {}
    }
    return context


def hash_password(pwd):
    """
    讲明文密码进行加密
    :param pwd: 明文密码
    :return: 经过sha256加密的密码
    """
    sha = hashlib.sha256()
    sha.update(pwd.encode("utf-8"))
    return sha.hexdigest()


def verify_code():
    """
    随机生成一个6位数的验证码
    :return:
    """
    code = ''
    for i in range(6):
        c_init = str(int(random.randint(1, 9)))
        code += c_init
    return code


def check_topic(topic_name, project_id):
    """
    如果topic_name存在，则检验是否符合规则
    若不存在，则生成一个topic_name
    """
    t = DfeTopic.objects.filter(project_id=project_id,topic_name=topic_name)
    if t.exists():
        raise Exception("此Topic名称已存在")
    if topic_name:

        new_name = re.match(r'(?:(?=.*[\-\_])(?=.*[A-Za-z])(?=.*[0-9]))\w{5,100}', topic_name).group()
        if len(new_name) != len(topic_name):
            raise Exception("topic名称格式错误")
        else:
            return new_name
    else:
        new_name = DfeProject.objects.get(projcet_id=project_id).project_name + "_" + \
                   str(DfeTopic.objects.filter(project_id=project_id).count() + 1)
        return new_name


def check_database(project_id, db_type):
    is_here = DfeDatabase.objects.filter(project_id=project_id, database_type=db_type)
    if is_here.exists():
        raise Exception("已存在同类型数据库，请勿重复创建！")
    else:
        return True


def create_db(db_type, project_id):
    db_name = "db_" + str(project_id)
    try:
        if db_type == "0":
            sql = "CREATE DATABASE {} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;".format(db_name)
            conn = pymysql.connect(host=settings.DATABASES['default']["HOST"],
                                   port=int(settings.DATABASES['default']["PORT"]),
                                   user=settings.DATABASES['default']["USER"],
                                   password=settings.DATABASES['default']["PASSWORD"],
                                   )
            cur = conn.cursor()
            if cur.execute("SELECT * FROM information_schema.SCHEMATA where SCHEMA_NAME='{}';".format(db_name)):
                content = make_false_dict()
                content["status"] = 5000
                content["errmsg"] = "the database already exists!"
                return content
            cur.execute(sql)
            conn.close()

        elif db_type == "1":
            try:
                # DATABASE = ['10.167.13.9', '10.167.13.16', '10.167.13.11', '10.167.13.12', '10.167.13.13']  # 数据库地址
                cluster = Cluster(settings.CASSANDRA_HOST,
                                  auth_provider=PlainTextAuthProvider(username=settings.CASSANDRA_USER,
                                                                      password=settings.CASSANDRA_PASSWORD))
                session = cluster.connect()
                session.execute(
                    "CREATE KEYSPACE %s WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': '3'} \
                      AND durable_writes = true;" % db_name)

                session.set_keyspace(db_name)
                session.shutdown()
            except Exception as e:
                content = make_false_dict()
                content["status"] = 5002
                content["errmsg"] = str(e)
                return response_origin(content)
        else:
            pass
    except Exception as e:
        content = make_false_dict()
        content["status"] = 5001
        content["errmsg"] = str(e)
        return response_origin(content)
    return "True"


def create_table(schema, tb_name, db_type, db_name):
    try:
        if db_type == "0":
            # sql = "CREATE DATABASE {} DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;".format(db_name)
            begin_sql = "CREATE TABLE %s(id int(11) PRIMARY KEY AUTO_INCREMENT," % tb_name
            middle_sql = ""
            for sch, sch_type in schema.items():
                stype, slength, scomment = sch_type.split("/")
                if stype in ["text", "datetime", "timestamp"]:
                    msql = sch + " " + stype + " " + " NOT NULL COMMENT '" + scomment + "', "
                else:
                    msql = sch + " " + stype + "(" + slength + ")" + " NOT NULL COMMENT '" + scomment + "', "
                middle_sql += msql
                
            end_sql = ")ENGINE=InnoDB DEFAULT CHARSET='utf8';"
            final_sql = begin_sql + middle_sql[:-2] + end_sql
            conn = pymysql.connect(host=settings.DATABASES['default']["HOST"],
                                   port=int(settings.DATABASES['default']["PORT"]),
                                   user=settings.DATABASES['default']["USER"],
                                   password=settings.DATABASES['default']["PASSWORD"],
                                   db=db_name,
                                   charset='utf8'
                                   )
            cur = conn.cursor()
            cur.execute(final_sql)
            conn.close()
            return True
        elif db_type == "1":
            begin_cql = "CREATE TABLE {}.{} (".format(db_name, tb_name)
            middle_cql = "device_name text, msg_id int, timestamp timestamp,"
            pkey = ["device_name","msg_id","timestamp"]
            skey = ["msg_id ASC","timestamp DESC"]
            schema1 = schema["payload"] if isinstance(schema["payload"], dict) else eval(schema["payload"])
            for sch, sch_type in sorted(schema1.items()):
                ctype, primary_key, sort_key = sch_type.split("/")
                cql = sch + " " + ctype + ", "
                if primary_key == "primary_key":
                    pkey.append(sch)
                if sort_key != "None":
                    skey.append(sch + " " + sort_key)
                middle_cql += cql
            mid_cql = middle_cql + "PRIMARY KEY " + str(tuple(pkey)).replace("\'",
                                                                             "") + " ) WITH CLUSTERING ORDER BY " + str(
                tuple(skey)).replace("\'", "")
            end_cql = """    AND bloom_filter_fp_chance = 0.01
    AND caching = {'keys': 'ALL', 'rows_per_partition': 'NONE'}
    AND comment = ''
    AND compaction = {'class': 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy', 'max_threshold': '32', 'min_threshold': '4'}
    AND compression = {'chunk_length_in_kb': '64', 'class': 'org.apache.cassandra.io.compress.LZ4Compressor'}
    AND crc_check_chance = 1.0
    AND dclocal_read_repair_chance = 0.1
    AND default_time_to_live = 0
    AND gc_grace_seconds = 864000
    AND max_index_interval = 2048
    AND memtable_flush_period_in_ms = 0
    AND min_index_interval = 128
    AND read_repair_chance = 0.0
    AND speculative_retry = '99PERCENTILE';
"""
            final_cql = begin_cql + mid_cql + end_cql
            # DATABASE = ['10.167.13.9', '10.167.13.16', '10.167.13.11', '10.167.13.12', '10.167.13.13']  # 数据库地址
            cluster = Cluster(settings.CASSANDRA_HOST,
                              auth_provider=PlainTextAuthProvider(username=settings.CASSANDRA_USER,
                                                                  password=settings.CASSANDRA_PASSWORD))
            session = cluster.connect(db_name)
            session.execute(final_cql)
            session.shutdown()
        else:
            pass
    except Exception as e:
        raise Exception("创建表失败,%s" % str(e))


def create_topic(topic_name, partition_number):
    try:
        location = "%s/kafka-topics.sh --create --zookeeper %s --replication-factor 3 --partitions %s  --topic %s " % (
            settings.KAFKA_DICTIONARY, settings.KAFKA_ADDRESS + ":2181", partition_number, topic_name)
        scs = SSHClinetServer(host=settings.KAFKA_ADDRESS, port=22, user=settings.KAFKA_USER,
                              password=settings.KAFKA_PASSWORD)  # 連接服務器
        # if scs.login_server():
        #     out_content = scs.execute_cmd(CMD_LIST[0] % settings.KAFKA_DICTIONARY)[1]
        #     file_list = [content.replace('\n', '') for content in out_content.readlines()]
        #     raise Exception("已经登录主机%s" % file_list)
        # else:
        #     out_content = scs.execute_cmd(CMD_LIST[0] % settings.KAFKA_DICTIONARY)[1]
        #     file_list = [content.replace('\n', '') for content in out_content.readlines()]
        #     raise Exception("未登录到主机%s" % file_list)
        scs.login_server()
        out_content = scs.execute_cmd(location)[1]  # 輸入Linux命令
        # raise Exception("输出为%s" % out_content.readlines())
        # scs.logout_server()

        return True
    except Exception as e:
        raise Exception(str(e))
